package com.zyt.springboot.teach_bigDecimal;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;

@SuppressWarnings("all")
public class TeachBigDecimal {
    public static void main(String[] args) {
        //Double类型只能处理16位有效数字精度
        //实际开发中，对于价格方面，税率计算double类型精度是远远不够的
        double dd = 5.55555555555555555555555555555555555555555;
        System.out.println("double:"+dd);
        //因此我们就需要BigDecimal这个类型进行储值计算，防止精度丢失
        //先new两个BigDecimal类型的数字，这里必须是有参的，没有无参构造
        //并且必须用双引号包裹，也就是必须放字符串类型的值，
        //不带引号会引起精度损失，并且会损失16位有效数字以后的精度！！！
        //这里提问，为什么会损失16位以后的精度？
        //这里提问，为什么不加引号默认传入的时double类型？不是float类型？
        BigDecimal bd1 = new BigDecimal(5.55555555555555555555555555555555555555555);
        BigDecimal bd2 = new BigDecimal("5.55555555555555555555555555555555555555555");
        System.out.println("不带引号："+bd1);
        System.out.println("带引号："+bd2);
        //精度类MathContext
        //手动控制精度
        MathContext mathContext3 = new MathContext(3);//3指的是三位有效数字
        //官方提供的精度
        //MathContext.UNLIMITED=不限制精度，采用四舍五入
        //MathContext.DECIMAL32=7位有效数字
        //MathContext.DECIMAL64=16位有效数字
        //MathContext.DECIMAL128=34位有效数字
        //点源码看看为什么时32对应7位有效数字？
        //这里有0就会算进去，没有0也不会在自动补
        BigDecimal bd3 = new BigDecimal("1.2345678901234567890123456789012345678901234567890",mathContext3);
        BigDecimal bdu = new BigDecimal("1.2345678901234567890123456789012345678901234567890",MathContext.UNLIMITED);
        BigDecimal bd7 = new BigDecimal("1.2345678901234567890123456789012345678901234567890",MathContext.DECIMAL32);
        BigDecimal bd16 = new BigDecimal("1.2345678901234567890123456789012345678901234567890",MathContext.DECIMAL64);
        BigDecimal bd34 = new BigDecimal("1.2345678901234567890123456789012345678901234567890",MathContext.DECIMAL128);
        BigDecimal bd34x = new BigDecimal("1.23",MathContext.DECIMAL128);//不会自动补充缺少的0
        System.out.println("3位有效数字："+bd3);
        System.out.println("不限制有效数字："+bdu);
        System.out.println("7位有效数字："+bd7);
        System.out.println("16位有效数字："+bd16);
        System.out.println("34位有效数字："+bd34);
        System.out.println("34位有效数字："+bd34x);

        //四则运算
        BigDecimal a = new BigDecimal("5.55555");
        BigDecimal b = new BigDecimal("4.55554");
        //1.加法add
        BigDecimal add = a.add(b);
        System.out.println("加法："+add);
        //2.减法subtract
        BigDecimal subtract = a.subtract(b);
        System.out.println("减法："+subtract);
        //3.乘法multiply
        BigDecimal multiply = a.multiply(b);
        System.out.println("乘法："+multiply);
        //4.除法divide，必须有舍入模式，没有会报错，ArithmeticException算数异常
        BigDecimal divide = a.divide(b,MathContext.DECIMAL32);//七位有效数字
        BigDecimal divide2 = a.divide(b,RoundingMode.HALF_UP);//四舍五入
        System.out.println("除法(七位有效数字)："+divide);
        System.out.println("除法(四舍五入)："+divide2);
        //拓展，舍入模式，八种
        /*
        1.ROUND_UP
        远离0的舍入模式
        2.ROUND_DOWN
        接近0的舍入模式
        3.ROUND_CEILING
        接近正无穷大的舍入模式
        4.ROUND_FLOOR
        接近负无穷大的舍入模式
        5.ROUND_HALF_UP
        四舍五入
        6.ROUND_HALF_DOWN
        五舍六入
        7.ROUND_HALF_EVEN
        四舍六入，五看情况，左边一位奇数入，偶数舍，也叫银行家舍入法（美国使用）
        8.ROUND_UNNECESSARY
        不舍入，前提时要有具体的结果，不能是循环小数
        */
        //如果我有一个数字，我不想计算，我想直接舍入，可以吗？
        //除以1就好了
        BigDecimal c = new BigDecimal("-4.55554");
        BigDecimal cc = c.divide(BigDecimal.ONE,3,RoundingMode.HALF_EVEN);//3表示精确到小数点后3位
        System.out.println("银行家舍入法："+cc);
        //5.取模
        BigDecimal remainder = a.remainder(b);
        System.out.println("取模"+remainder);
        //6.绝对值abs
        BigDecimal d = new BigDecimal("-1.55");
        BigDecimal abs = d.abs();
        System.out.println("绝对值："+abs);
        //7.n次方
        BigDecimal e = new BigDecimal("5");
        BigDecimal pow = e.pow(3);
        System.out.println("3次方："+pow);
        //8.小数点左移，小数点右移
        BigDecimal f = new BigDecimal("123.456");
        BigDecimal left = f.movePointLeft(4);
        BigDecimal right = f.movePointRight(4);
        System.out.println("小数点左移4位："+left);
        System.out.println("小数点左移4位："+right);
        //9.去掉末尾没用的0
        BigDecimal g = new BigDecimal("123.45600000000000");
        BigDecimal stripTrailingZeros = g.stripTrailingZeros();
        System.out.println("去掉0："+stripTrailingZeros);
        //温馨小提示：
        /*
        在使用BigDecimal来进行数据操作时，
        一定要避免使用BigDecimal为空的情况
        否则就会在运行时抛出NullPointerException：空指针异常
        为了避免此情况的发生
        new这个BigDecimal的时候可以调用他本身的枚举
        比如BigDecimal.ZERO，BigDecimal.ONE，BigDecimal.TEN
        */
        BigDecimal bb0 = BigDecimal.ZERO;
        BigDecimal bb1 = BigDecimal.ONE;
        BigDecimal bb10 = BigDecimal.TEN;
        //这里也可以点源码看看枚举内容
        System.out.println(bb0);
        System.out.println(bb1);
        System.out.println(bb10);
    }
}
